//
//  HomeTableViewController.swift
//  FeastBooking
//
//  Created by Imon on 2017/7/6.
//  Copyright © 2017年 Imon. All rights reserved.
//

import UIKit
import IGListKit
import RxSwift
import ReachabilitySwift

class HomeTableViewController: UIViewController {
    
    fileprivate let activityView: UIActivityIndicatorView = {
        let view = UIActivityIndicatorView(activityIndicatorStyle: .gray)
        view.startAnimating()
        return view
    }()
    
    let emptyView: EmptyView = {
        let ev = EmptyView()
        return ev
    }()
    
    let reachability = Reachability()
    
    let authManager = AuthManager.share
    
    let pageNum: Int = 10
    
    lazy var items: [ListDiffable] = []
    let advertisementVM = AdvertisementViewModel.share
    let recommendationVM = RecommendationViewModel.share
    let restaurantVM = RestaurantViewModel.share
    
    let disposeBag = DisposeBag()
    
    let loginBar: LoginBar = LoginBar()
    
    var urls: [String] = []
    var recommendations: [RecommendationResponse] = []
    var restaurants: [RestaurantSummaryResponse] = []
    var page: Int = 0
    var sortString: String = ""
    var sorting = false
    var isEnd = false
    var minRating: String = ""
    var minPrice: String = ""
    var maxPrice: String = ""
    var name: String = ""
    var filtered = false
    
    var timer: Timer = Timer()
    
    var filterButtons: [FilterButton] = []
    var loading = false
    let spinToken = "spinner"
    
    let collectionView: UICollectionView = {
        let view = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
        view.backgroundColor = lightSaperatorColor
        return view
    }()
    
    lazy var adapter: ListAdapter = {
        return ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 0)
    }()
    
    let endingView: EndingView = {
        let ev = EndingView()
        return ev
    }()
    
    var checkLoadTimes = 0
    
    var adLoadFinish = false
    
    var recoLoadFinish = false
    
    var restLoadFinish = false
    
    var adShowFinish = false
    
    var recoShowFinish = false
    
    var restShowFinish = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.title = LanguageHelper.getString(key: "FEAST_RESTAURANTS")
        setFilterButton()
        
        adapter.dataSource = self
        //adapter.scrollViewDelegate = self 转移到初始数据加载之后再执行
        adapter.collectionView = collectionView
        collectionView.alwaysBounceVertical = true
        loginBar.delegate = self
        
        self.view.addSubview(activityView)
        self.view.addSubview(loginBar)
        
        self.emptyView.delegate = self
        
        if (reachability?.isReachable)! {
            loadData()
            timer = Foundation.Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(checkDataLoad), userInfo: nil, repeats: true)
        } else {
            activityView.stopAnimating()
//            collectionView.removeFromSuperview()
//            self.view.addSubview(emptyView)
            self.showPromptView(message: LanguageHelper.getString(key: "UNREACHABLE"), confirmText: LanguageHelper.getString(key: "OK"))
        }
    }
    
    func checkDataLoad() {
//        if urls.count > 0 || recommendations.count > 0 || restaurants.count > 0 {
//            activityView.stopAnimating()
//
//            let recommendTitle = Title(value: "特別推介")
//
//            let tableTitle = Title(value: "所有酒樓")
//
//            if urls.count > 0 {
//                items.append(urls as ListDiffable)
//            }
//            if recommendations.count > 0 {
//                items.append(recommendTitle as ListDiffable)
//                items.append(recommendations as ListDiffable)
//            }
//            items.append(tableTitle as ListDiffable)
//
//            if restaurants.count > 0 {
//                for restaurant in restaurants {
//                    items.append(restaurant as ListDiffable)
//                }
//                adapter.scrollViewDelegate = self
//            }
//
//            adapter.performUpdates(animated: true, completion: nil)
//            timer.invalidate()
//        }
        if adLoadFinish && !adShowFinish {
            if urls.count > 0 {
                items.append(urls as ListDiffable)
                adapter.performUpdates(animated: true, completion: nil)
            }
            adShowFinish = true
        }
        if adShowFinish && recoLoadFinish && !recoShowFinish {
            if recommendations.count > 0 {
                let recommendTitle = Title(value: LanguageHelper.getString(key:     "SP_RECOMMEND"))
                items.append(recommendTitle as ListDiffable)
                items.append(recommendations as ListDiffable)
                adapter.performUpdates(animated: true, completion: nil)
            }
            recoShowFinish = true
        }
        if adShowFinish && recoShowFinish && restLoadFinish && !restShowFinish {
            if restaurants.count > 0 {
                let tableTitle = Title(value: LanguageHelper.getString(key: "RESTAURANTS"))
                items.append(tableTitle as ListDiffable)
                for restaurant in restaurants {
                    items.append(restaurant as ListDiffable)
                }
                adapter.scrollViewDelegate = self
                adapter.performUpdates(animated: true, completion: nil)
                timer.invalidate()
                activityView.stopAnimating()
            }
            recoShowFinish = true
        }
        if checkLoadTimes >= 8 {
            timer.invalidate()
            activityView.stopAnimating()
            if !(urls.count > 0 || recommendations.count > 0 || restaurants.count > 0) {
//                collectionView.removeFromSuperview()
//                self.view.addSubview(emptyView)
            }
        }
        checkLoadTimes += 1
    }
    
    func loadData() {
        items = []
        restaurants = []
        urls = []
        recommendations = []
        page = 0
        checkLoadTimes = 0
        adapter.scrollViewDelegate = nil
        adapter.performUpdates(animated: true, completion: nil)
        activityView.startAnimating()
        view.insertSubview(collectionView, belowSubview: activityView)
        advertisementVM.getAdvertisements().subscribe(onNext: { ads in
            for ad in ads {                
                self.urls.append(ad.picUrl!)
            }
            self.adLoadFinish = true
        })
        .addDisposableTo(disposeBag)
        
        recommendationVM.getRecommendations().subscribe(onNext: { ros in
            for ro in ros {
                self.recommendations.append(ro)
            }
            self.recoLoadFinish = true
        })
        .addDisposableTo(disposeBag)
        
        restaurantVM.getRestaurants(page: page, sort: sortString, minRating: minRating, minPrice: minPrice, maxPrice: maxPrice, name: name).subscribe(onNext: { rests in
            for rest in rests {
                self.restaurants.append(rest)
            }
            if rests.count == self.pageNum {
                self.isEnd = false
            } else {
                self.isEnd = true
//                self.endingView.frame = CGRect(x: 0, y: self.collectionView.contentSize.height, width: self.collectionView.frame.width, height: 20)
//                self.collectionView.addSubview(self.endingView)
            }
            self.restLoadFinish = true
        })
        .addDisposableTo(disposeBag)
        self.page += 1
    }
    
    override func viewWillAppear(_ animated: Bool) {
        if authManager.hasLogined() {
            loginBar.removeFromSuperview()
        } else {
            self.view.addSubview(loginBar)
        }
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.frame = CGRect(x: 0, y: 36, width: self.view.bounds.width, height: self.view.bounds.height - 36)
        emptyView.frame = CGRect(x: 0, y: 36, width: self.view.bounds.width, height: self.view.bounds.height - 36)
        let barHeight: CGFloat = 50
        loginBar.frame = CGRect(x: 0, y: self.view.bounds.height - barHeight, width: self.view.bounds.width, height: barHeight)
        activityView.center = CGPoint(x: collectionView.frame.width/2.0, y: collectionView.frame.height/2.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    @IBAction func search(_ sender: UIBarButtonItem) {
        let searchPage = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "SearchViewController") as! SearchViewController
        searchPage.completion = { search in
            self.filterButtons[self.filterButtons.count - 1].filtered()
            self.filtered = true
            self.name = search
            self.updateCollectionView()
        }
        searchPage.hidesBottomBarWhenPushed = true
        self.navigationController?.pushViewController(searchPage, animated: true)
    }
    
    func filter(_ sender: UITapGestureRecognizer) {
        if !filtered {
            let filterPage = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "FilterViewController") as! FilterViewController
            filterPage.hidesBottomBarWhenPushed = true
            filterPage.completion = { [unowned self] minRating, minPrice, maxPrice in
                self.filterButtons[self.filterButtons.count - 1].filtered()
                self.filtered = true
                self.minRating = minRating
                self.minPrice = minPrice
                self.maxPrice = maxPrice
                self.updateCollectionView()
            }
            self.navigationController?.pushViewController(filterPage, animated: true)
        } else {
            self.filtered = false
            self.minRating = ""
            self.minPrice = ""
            self.maxPrice = ""
            self.name = ""
            self.filterButtons[self.filterButtons.count - 1].unfilterd()
            self.updateCollectionView()
        }
    }
    
    func setFilterButton() {
        let overall = FilterButton()
        overall.nameLabel.text = LanguageHelper.getString(key: "OVERALL")
        overall.image = UIImage(named: "sort")
        overall.selectedImage = UIImage(named: "sort_1")
        overall.sortAscString = "rating,asc"
        overall.sortDescString = "rating,desc"
        overall.imageView.image = overall.image
        
        let orders = FilterButton()
        orders.nameLabel.text = LanguageHelper.getString(key: "ORDER")
        orders.image = UIImage(named: "sort")
        orders.selectedImage = UIImage(named: "sort_1")
        orders.sortAscString = "numOfOrders,asc"
        orders.sortDescString = "numOfOrders,desc"
        orders.imageView.image = orders.image
        
        let price = FilterButton()
        price.nameLabel.text = LanguageHelper.getString(key: "PRICE")
        price.image = UIImage(named: "sort")
        price.selectedImage = UIImage(named: "sort_1")
        price.sortAscString = "minimumPrice,asc"
        price.sortDescString = "maximumPrice,desc"
        price.imageView.image = price.image
        
        let filter = FilterButton()
        filter.nameLabel.text = LanguageHelper.getString(key: "FILTER")
        filter.image = UIImage(named: "filter")
        filter.selectedImage = UIImage(named: "filter_1")
        filter.imageView.image = filter.image
        let filterTapGR = UITapGestureRecognizer()
        filterTapGR.addTarget(self, action: #selector(filter(_:)))
        filter.addGestureRecognizer(filterTapGR)
        
        filterButtons += [overall, orders, price, filter]
        
        let buttonWidth: CGFloat = 50
        let leading: CGFloat = 15
        let gap: CGFloat = (self.view.bounds.width - 2 * leading - buttonWidth * CGFloat(filterButtons.count)) / CGFloat(filterButtons.count - 1)
        
        for i in 0...filterButtons.count - 1 {
            filterButtons[i].frame = CGRect(x: leading + buttonWidth * CGFloat(i) + gap * CGFloat(i), y: 8, width: buttonWidth, height: 20)
            self.filterButtons[i].layoutSubviews()
            self.view.addSubview(filterButtons[i])
        }
    }
    
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let point = touch.location(in: self.view)
            for i in 0...filterButtons.count - 2 {
                if filterButtons[i].frame.contains(point) {
                    touchAt(index: i)
                    break
                }
            }
        }
    }

    func touchAt(index: Int) {
        if !loading && !sorting && restaurants.count > 0 { //防止排序时被重复点击 //防止加载更多时点击排序
            sortString = filterButtons[index].touch()
            for i in 0...filterButtons.count - 2 {
                if i != index {
                    filterButtons[i].reset()
                }
            }
            sorting = true
            updateCollectionView()
        }
    }
    
    func updateCollectionView() {
        self.endingView.removeFromSuperview()
        self.isEnd = false
        items = []
        restaurants = []
        page = 0
        checkLoadTimes = 0
        restLoadFinish = false
        adapter.performUpdates(animated: true, completion: nil)
        adapter.scrollViewDelegate = nil
        activityView.startAnimating()
        loadSortedFilteredRestaurant()
        timer = Foundation.Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(checkSortedRestaurant), userInfo: nil, repeats: true)
    }
    
    func loadSortedFilteredRestaurant() {
        restaurantVM.getRestaurants(page: page, sort: sortString, minRating: minRating, minPrice: minPrice, maxPrice: maxPrice, name: name).subscribe(onNext: { [unowned self] rests in
            for rest in rests {
                self.restaurants.append(rest)
            }
            if rests.count == self.pageNum {
                self.isEnd = false
            } else {
                self.isEnd = true
            }
            self.restLoadFinish = true
        })
        .addDisposableTo(disposeBag)
        self.page += 1
    }
    
    func checkSortedRestaurant() {
        if restLoadFinish {
            activityView.stopAnimating()
            if restaurants.count > 0 {
                let recommendTitle = Title(value: LanguageHelper.getString(key: "SP_RECOMMEND"))
            
                let tableTitle = Title(value: LanguageHelper.getString(key: "RESTAURANTS"))
            
                if urls.count > 0 {
                    items.append(urls as ListDiffable)
                }
                if recommendations.count > 0 {
                    items.append(recommendTitle as ListDiffable)
                    items.append(recommendations as ListDiffable)
                }
                items.append(tableTitle as ListDiffable)
            
                for restaurant in restaurants {
                    items.append(restaurant as ListDiffable)
                }
                
            } else {
                if urls.count > 0 {
                    items.append(urls as ListDiffable)
                }
                if recommendations.count > 0 {
                    let recommendTitle = Title(value: LanguageHelper.getString(key: "SP_RECOMMEND"))
                    items.append(recommendTitle as ListDiffable)
                    items.append(recommendations as ListDiffable)
                }
                if urls.count == 0 && recommendations.count == 0 {
                    activityView.stopAnimating()
//                    collectionView.removeFromSuperview()
//                    self.view.addSubview(emptyView)
                }
            }
            adapter.performUpdates(animated: true, completion: nil)
            timer.invalidate()
            adapter.scrollViewDelegate = self
            sorting = false
        } else if checkLoadTimes >= 5 {
            activityView.stopAnimating()
            if urls.count > 0 {
                items.append(urls as ListDiffable)
            }
            if recommendations.count > 0 {
                let recommendTitle = Title(value: LanguageHelper.getString(key: "SP_RECOMMEND"))
                items.append(recommendTitle as ListDiffable)
                items.append(recommendations as ListDiffable)
            }
            if urls.count == 0 && recommendations.count == 0 {
                activityView.stopAnimating()
//                collectionView.removeFromSuperview()
//                self.view.addSubview(emptyView)
            }
            adapter.performUpdates(animated: true, completion: nil)
            timer.invalidate()
            adapter.scrollViewDelegate = self
            sorting = false
        }
        checkLoadTimes += 1
    }
}

extension HomeTableViewController: ListAdapterDataSource {
    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        var objects = items as [ListDiffable]
        
        if loading {
            objects.append(spinToken as ListDiffable)
        }
        
        return objects
    }
    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
        switch object {
        case is [String]:
            return AdvertisementSectionController()
        case is [RecommendationResponse]:
            let sc = RecommendationSectionController()
            sc.delegate = self
            return sc
        case is Title:
            return TitleSectionController()
        case is String:
            return spinnerSectionController()
        default:
            let sectionController = RestaurantSectionController()
            sectionController.delegate = self
            return sectionController
        }
    }
    func emptyView(for listAdapter: ListAdapter) -> UIView? {
        return self.emptyView
    }
}

extension HomeTableViewController: UIScrollViewDelegate {
    //下拉加载更多
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        let distance = scrollView.contentSize.height - (targetContentOffset.pointee.y + scrollView.bounds.height)
        if !loading && !isEnd && distance < 150 {
            self.loading = true
            self.adapter.performUpdates(animated: true, completion: nil)
            DispatchQueue.global(qos: .default).async {                
                sleep(2)
                self.restaurantVM.getRestaurants(page: self.page, sort: self.sortString, minRating: self.minRating, minPrice: self.minPrice, maxPrice: self.maxPrice, name: self.name).subscribe(onNext: { rests in
                    for rest in rests {
                        //self.restaurants.append(rest)
                        self.items.append(rest as ListDiffable)
                    }
                    self.adapter.performUpdates(animated: true, completion: nil)
                    if rests.count == self.pageNum {
                        self.isEnd = false
                    } else {
                        self.isEnd = true
                    }
                })
                .addDisposableTo(self.disposeBag)
                self.page += 1                
                DispatchQueue.main.async {
                    //加载更多
                    self.loading = false
                    self.adapter.performUpdates(animated: true, completion: nil)
                }
            }
        } else if isEnd {
            self.endingView.frame = CGRect(x: 0, y: self.collectionView.contentSize.height + 10, width: self.view.frame.width, height: 25)
            self.collectionView.addSubview(self.endingView)
        }
    }
}

extension HomeTableViewController: RestaurantCollectionSectionDelegate {
    
    func detailPage(of restaurantS: RestaurantSummaryResponse!) {
        restaurantVM.getRestaurant(id: restaurantS.id!).subscribe(onNext: { restaurant in
            if let status = restaurant.status, status != 200 {
                self.showPromptView(message: LanguageHelper.getString(key: "ERROR_OCCUR"), confirmText: LanguageHelper.getString(key: "OK"))
            } else {
                let detailPage = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "RestaurantDetailViewController") as! RestaurantDetailViewController
                detailPage.restaurant = restaurant
                detailPage.hidesBottomBarWhenPushed = true
                if let noc = restaurantS.numOfReviews, noc > 0 {
                    detailPage.numOfComments = noc
                }
                self.navigationController?.pushViewController(detailPage, animated: true)
            }
        })
        .addDisposableTo(disposeBag)
    }
}

extension HomeTableViewController: LoginBarDelegate {
    
    func showLoginView() {
        showLoginPage()
    }
}

extension HomeTableViewController: RecommendationSectionControllerDelegate {
    
    func showRestaurant(id: Int) {
        restaurantVM.getRestaurant(id: id).subscribe(onNext: { restaurant in
            if let status = restaurant.status, status != 200 {
                self.showPromptView(message: LanguageHelper.getString(key: "ERROR_OCCUR"), confirmText: LanguageHelper.getString(key: "OK"))
            } else {
                let detailPage = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "RestaurantDetailViewController") as! RestaurantDetailViewController
                detailPage.restaurant = restaurant
                detailPage.hidesBottomBarWhenPushed = true
                self.navigationController?.pushViewController(detailPage, animated: true)
            }
        })
        .addDisposableTo(disposeBag)
    }
}

extension HomeTableViewController: EmptyViewDelegate {
    
    func reload() {
        emptyView.removeFromSuperview()
        self.loadData()
        timer = Foundation.Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(checkDataLoad), userInfo: nil, repeats: true)
    }
}
